﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Runtime.InteropServices;
using System.Threading;

using canlibCLSNET;


namespace CANMonitor
{
	public class CanAlyst_Kvaser	// 一个 CanAlyst_II盒，有两个Can收发器
	{
		
		// -------------------------------------------------------------------------------------------------------
		#region 0. 类静态操作，诸如查询各个Device信息 等
		static private bool IsCanLib_Inited = false;

		static public string[] GetPortNames()
		{
			if (IsCanLib_Inited == false)
			{
				Canlib.canInitializeLibrary();
				IsCanLib_Inited = true;
			}

            Canlib.canStatus status = new Canlib.canStatus();
            int channel_count = 0;

            Canlib.canGetNumberOfChannels(out channel_count);
			string[] ret = new string[channel_count];

            Console.WriteLine("First argument must be a channel!\n");
            Console.WriteLine("Channel\t Name");
            Console.WriteLine("--------------------------------------------------------");
            for (int i = 0; (status == Canlib.canStatus.canOK) && (i < channel_count); i++)
            {
                object chData;
                status = Canlib.canGetChannelData(i, Canlib.canCHANNELDATA_CHANNEL_NAME, out chData);
				ret[i] = chData.ToString();
            }
			return ret;
		}

		#endregion


		// -------------------------------------------------------------------------------------------------------
		#region 1. Device 的操作，包括断线重连管理

		private const UInt32 m_device_type = 4;
		private Int32 m_device_index;

		private bool m_device_IsOpen = false;
		private Timer m_100ms_Timer;

		private void check(string info, Canlib.canStatus stat)
		{
			if (stat != Canlib.canStatus.canOK)
			{
				string buf="";
				Canlib.canGetErrorText(stat, out buf);
				Console.WriteLine("%s: failed, stat=%d (%s)\n", m_device_index, (int)stat, buf);

			}
		}


		public CanAlyst_Kvaser()
		{
			m_100ms_Timer = new Timer(Device_100msTimer_Tick, null, 0, 100);
		}

		public void Device_Open(Int32 device_index)
		{
			Canlib.canStatus status;
			if (m_device_IsOpen == true)
				return;

			int hnd = Canlib.canOpenChannel(device_index, Canlib.canOPEN_CAN_FD | Canlib.canOPEN_NO_INIT_ACCESS);
			if (hnd < 0)
			{
				throw new Exception("打开CAN盒失败, id:" + device_index.ToString());
			}
			Canlib.canStatus stat1 = Canlib.canSetBusParams(hnd, Canlib.canFD_BITRATE_500K_80P, 0, 0, 0, 0, 0);
			Canlib.canStatus stat2 = Canlib.canSetBusParamsFd(hnd, Canlib.canFD_BITRATE_2M_80P, 0, 0, 0);
			check("canSetBusParams", stat1);
			check("canSetBusParamsFd", stat2);
			if (stat1 == Canlib.canStatus.canOK && stat2 == Canlib.canStatus.canOK)
			{
				m_device_index = hnd;
				m_device_IsOpen = true;

				//canDRIVER_NORMAL is set by default.
				//Canlib.canStatus stat = Canlib.canSetBusOutputControl(device_index, Canlib.canDRIVER_NORMAL);
				//check("ChangeMode Error", stat1);

				status = Canlib.canBusOn(hnd);
				//check("ChangeMode Error", status);
			}
			else
			{
				throw new Exception("打开CAN盒失败, id:" + device_index.ToString());
			}
		}

		public bool Device_Close()
		{
			if (m_device_IsOpen == false)
				return true;

			Canlib.canStatus stat = Canlib.canClose(m_device_index);
			if (stat < 0)
				return false;

			m_device_index = Canlib.canINVALID_HANDLE;
			m_device_IsOpen = false;
			return true;
		}

		public bool Device_Reset()
		{
			if (m_device_IsOpen == false)
				return false;

			//if (DLL_UsbDeviceReset() == VCI_OptionResult.VCI_Success)
			//{
			//    m_device_IsOpen = false;
			//    return true;
			//}
			return false;
		}

		public bool ReadBoardInfo(ref VCI_BOARD_INFO info)
		{
			//if (DLL_ReadBoardInfo(ref info) == VCI_OptionResult.VCI_Success)
			//    return true;

			return false;
		}

		private void Device_100msTimer_Tick(object o)
		{
			if (m_device_IsOpen == false)
				return;

			// 驱动CAN的接收
			bool result0 = CANx_Read_ProtBuffer(0);
			//bool result1 = CANx_Read_ProtBuffer(1);
			
			//断线重连
			//if (result0 == VCI_OptionResult.VCI_NoDevice || result1 == VCI_OptionResult.VCI_NoDevice)
			//{
			//    if (DLL_ConnectDevice() == VCI_OptionResult.VCI_Success)
			//    {
			//        Device_ReOpen();
			//        CANx_ReStart(0);
			//        CANx_ReStart(1);
			//    }
			//}
		}



		public bool Device_IsOpen()
		{
			//return DLL_ConnectDevice() == VCI_OptionResult.VCI_Success;
			return false;
		}

		#endregion


		//Len 要发送的帧结构体数组的长度（发送的帧数量）。最大为1000，建议设为1，每次发送单帧，以提高发送效率
		private bool Device_Transmit(CanMsg msg)
		{
			int id = (int)msg.mID; 
			int dlc = msg.mData.Length;
			int flag = 0; 
			if (msg.mIsExt) flag |= Canlib.canMSG_EXT;
			if (msg.mIsRtr) flag |= Canlib.canMSG_RTR;
			byte[] data = msg.mData;
			Canlib.canStatus sta = Canlib.canWrite(m_device_index, id, data, dlc, flag);
			if (sta == Canlib.canStatus.canOK)
				return true;
			else
			{
				return false;
			}
		}


		private List<CanMsg> Device_Receive(Int32 CANInd)
		{
			List<CanMsg> ret = new List<CanMsg>();
			while(true)
			{
				int id; byte[] msg = new byte[64]; int dlc; int flag; Int64 time;
				Canlib.canStatus sta = Canlib.canRead(m_device_index, out id, msg, out dlc, out flag, out time);
				if (sta == Canlib.canStatus.canERR_NOMSG)
					break;

				else if (sta == Canlib.canStatus.canOK)
				{
					byte[] data = new byte[dlc]; for (int i = 0; i < dlc; i++) data[i] = msg[i];
					CanMsg item = CanMsg.Parse((uint)time, (uint)id, data, false, (flag & Canlib.canMSG_EXT) != 0, (flag & Canlib.canMSG_RTR) != 0);
					ret.Add(item);
					continue;
				}

				else
					return null;//报告上层设备不存在 或 usb掉线
			}

			return ret;
		}

		// -------------------------------------------------------------------------------------------------------
		#region 2. 端口 的操作

		private List<CanMsg> m_CANx_RxBuff = new List<CanMsg>();

		public bool CANx_TransMsg(ref CanMsg msg)
		{
			return Device_Transmit(msg);
		}

		public bool CANx_TransMsg(int index, ref List<CanMsg> msg)
		{
			foreach (CanMsg item in msg)
			{
				bool ret = Device_Transmit(item);
				if (ret == false)
				{
					return false;
				}
			}

			return true;
		}

		public List<CanMsg> CANx_ReadMsg()
		{
			List<CanMsg> list = null;

			lock (m_CANx_RxBuff)
			{
				list = m_CANx_RxBuff;
				m_CANx_RxBuff = new List<CanMsg>();
			}

			return list;
		}


		//内部函数: 读取硬件缓存, 每隔30ms调用一次为宜
		private bool CANx_Read_ProtBuffer(int index)
		{
			if (m_device_IsOpen == false)
				return true; //商品未打开, 认为连接正常, 不要尝试重连了

			List<CanMsg> ret_msg = Device_Receive(index);
			if (ret_msg != null)
			{	
				lock (m_CANx_RxBuff) //缓存读到的消息
				{
					m_CANx_RxBuff.AddRange(ret_msg);
				}
				return true;
			}
			return false;
		}

		#endregion
	}


}
